package com.marquis.cloud.shiro.realm;

import com.marquis.cloud.entity.AutUser;
import com.marquis.cloud.utils.HttpInvoker;
import com.marquis.cloud.utils.JSONUtil;
import com.marquis.cloud.utils.PropertiesUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 自定义Realm授权与验证实现
 *
 * @author tyq 2016/1/14
 */
public class MyRealm extends AuthorizingRealm {


    /**
     * 授权
     * 注意：此方法需要登录成功后的跳转的jsp页面中加入Shiro的标签库和权限标签才能回调
     * <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
     * <shiro:hasRole name="user"></shiro:hasRole>
     * @param principals 用户信息
     * @return 授权结果
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //用户名
        String userName = (String) principals.getPrimaryPrincipal();
        // 授权
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //根据用户名查询用户信息
        PropertiesUtil pu = new PropertiesUtil();
        //查询当前用户拥有的角色
        String getRolesUrl = pu.getZuulUrl()+"/aut/user/getRoles";
        Map<String,Object> param = new HashMap<>();
        param.put("userName", userName);
        /*String rolesData = HttpInvoker.getInstance().invoke(getRolesUrl, param, true);
        if(!StringUtils.isEmpty(rolesData)){
            authorizationInfo.setRoles(JSONUtil.jsonToBean(rolesData, Set.class));
        }*/
        //查询当前用户拥有的权限
        String getPermissionsUrl = pu.getZuulUrl()+"/aut/user/getPermissions";
        /*String permissionsData = HttpInvoker.getInstance().invoke(getPermissionsUrl, param, true);
        if(!StringUtils.isEmpty(permissionsData)){
            authorizationInfo.setStringPermissions(JSONUtil.jsonToBean(permissionsData, Set.class));
        }*/
        Set<String> pers = new HashSet<>();
        pers.add("user:*");
        pers.add("user:add");
        pers.add("user:edit");
        pers.add("user:delete");
        pers.add("user:view");
        authorizationInfo.setStringPermissions(pers);
        return authorizationInfo;
    }

    /**
     * 认证
     * @param token 认证信息
     * @return 认证结果
     * @throws AuthenticationException 异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //登录的主要信息,可以是一个实体对象，但该实体类的对象必须是根据token的username查询得到的
        //用户名
        Object principal = token.getPrincipal();
        //根据用户名查询用户信息
        PropertiesUtil pu = new PropertiesUtil();
        //请求地址
        String url = pu.getZuulUrl()+"/aut/user/findByUserName";
        Map<String,Object> param = new HashMap<>();
        param.put("userName", principal);
        String data = HttpInvoker.getInstance().invoke(url, param, true);
        //认证信息,从数据库中查询出来的信息,密码的比对交给shiro去比较
        if (StringUtils.isEmpty(data)){
            throw new UnknownAccountException("用户名或密码错误");
        }
        AutUser autUser = JSONUtil.jsonToBean(data, AutUser.class);
        //密码
        String credentials = autUser.getPassword();
        if ("N".equals(autUser.getEnableFlag())){
            throw new LockedAccountException("用户已锁定");
        }
        //MD5盐
        ByteSource sale = ByteSource.Util.bytes(principal);
        return new SimpleAuthenticationInfo(principal, credentials, sale, getName());
    }

    /**
     * 设置密码加密方式
     */
    public void setCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        setCredentialsMatcher(credentialsMatcher);
    }

    public static void main(String[] args) {
        //盐值
        String saleSource = "sale";
        //明文密码
        String password = "11111";
        String md5Pwd = new SimpleHash("MD5", password, saleSource).toString();
        System.out.println(md5Pwd);
    }
}
